package org.microboot.logging.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.microboot.core.bean.ApplicationContextHolder;
import org.microboot.core.constant.Constant;
import org.microboot.core.func.Func1;
import org.springframework.core.annotation.Order;

/**
 * @author 胡鹏
 */
@Aspect
@Order(0)
public class LoggingAspect {

    /**
     * 说明1：@annotation只能针对方法，为了增加在类上使用注解的功能，考虑使用@whith或@target
     *
     * 说明2：假设执行son.f()
     * 1、如果是@target(A)：会查看调用f()方法的son对象的S类上是否有注解A
     * 2、如果是@withn(A)：会查看f()方法所属的P类上是否有注解A
     * 总结：关键在于：一个针对的是对象，一个针对的是所属的类
     * 参考：https://blog.csdn.net/hikisan/article/details/118676615
     *
     * 上面是网上资料，我自己做了两个实验，分别在Spring和SpringBoot环境下
     * 1、Spring环境下的实验中，@target大多时候会不生效
     * 2、SpringBoot环境下的实验中，@target会报BeanCreationException异常
     * 实验1在mashibing-spring项目的com.mashibing.spring.test.aop.scan.annotation包下
     * 实验2在microboot-test-web6项目下
     * 参考：https://blog.csdn.net/hello_qaz123/article/details/131819865
     *
     * 因此最终决定使用@within
     */
    @Pointcut("@annotation(org.microboot.logging.annotation.Logging) || @within(org.microboot.logging.annotation.Logging)")
    public void cut() {
    }

    @SuppressWarnings("unchecked")
    @Around("cut()")
    public Object aroundAspect(final ProceedingJoinPoint joinPoint) throws Exception {
        return ApplicationContextHolder.getBean(Constant.LOGGING_FUNC, Func1.class).func(joinPoint);
    }
}
